Skip to content

feat(ui): Mosaic field component - #9322

Open
austincalvelage wants to merge 14 commits into
mainfrom
mosaic-text-field-component
Open

feat(ui): Mosaic field component#9322
austincalvelage wants to merge 14 commits into
mainfrom
mosaic-text-field-component

Conversation

@austincalvelage

@austincalvelage austincalvelage commented Aug 4, 2026

Copy link
Copy Markdown
Member

Description

https://swingset-git-mosaic-text-field-component.clerkstage.dev/components/field

CleanShot 2026-08-04 at 16 02 31@2x CleanShot 2026-08-04 at 16 01 40@2x

Adds the Mosaic Field component:

  • Adds the compound Field.Root, Field.Label, Field.Description, and Field.Error API.
  • Connects labels, descriptions, and errors to a composed Mosaic control using generated or caller-provided IDs and the appropriate aria-* attributes.
  • Emits a consistent generated control and label relationship during server rendering; caller-provided control IDs and registered message relationships finalize during hydration.
  • Propagates invalid, disabled, and required to composed Mosaic inputs.
  • Provides styled error presentation with an alert-circle icon. Validation, error visibility, and lifecycle state such as dirty, touched, filled, and focused remain caller-owned.
import { Field } from '@clerk/ui/mosaic/components/field';
import { Input } from '@clerk/ui/mosaic/components/input';

<Field.Root required>
  <Field.Label>Email address</Field.Label>
  <Input
    name='email'
    type='email'
  />
  <Field.Description>Used for account notifications.</Field.Description>
</Field.Root>;

@changeset-bot

changeset-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 1bcc702

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 0 packages

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview Aug 11, 2026 8:29pm
swingset Ready Ready Preview Aug 11, 2026 8:29pm

Request Review

@pkg-pr-new

pkg-pr-new Bot commented Aug 4, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@9322

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@9322

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@9322

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@9322

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@9322

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@9322

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@9322

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@9322

@clerk/expo-google-signin

npm i https://pkg.pr.new/@clerk/expo-google-signin@9322

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@9322

@clerk/express

npm i https://pkg.pr.new/@clerk/express@9322

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@9322

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@9322

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@9322

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@9322

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@9322

@clerk/react

npm i https://pkg.pr.new/@clerk/react@9322

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@9322

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@9322

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@9322

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@9322

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@9322

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@9322

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@9322

commit: 1bcc702

@austincalvelage
austincalvelage force-pushed the mosaic-text-field-component branch from 57aeff6 to fd49235 Compare August 4, 2026 20:48
@austincalvelage austincalvelage changed the title feat(ui):Mosaic text field component feat(ui): Mosaic text field component Aug 4, 2026
@austincalvelage austincalvelage changed the title feat(ui): Mosaic text field component feat(ui): Mosaic field component Aug 4, 2026
@austincalvelage
austincalvelage force-pushed the mosaic-text-field-component branch from ca96e1b to a6c399c Compare August 4, 2026 23:01
@austincalvelage
austincalvelage force-pushed the mosaic-text-field-component branch from ee83a6e to fcbd583 Compare August 5, 2026 03:25
@austincalvelage
austincalvelage force-pushed the mosaic-text-field-component branch from fcbd583 to 374b29c Compare August 5, 2026 04:08
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Added the Mosaic Field component with Root, Label, Description, and Error parts. Added context-based control IDs and ARIA relationships to Input. Added styling, an alert icon, public exports, SSR and interaction tests, Storybook documentation, and Swingset registry entries.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • clerk/javascript#9309: This PR extends the Mosaic Input component by integrating Field context and accessibility props.

Suggested reviewers: alexcarpenter, maxyinger

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the main change: adding the Mosaic Field component.
Description check ✅ Passed The description directly explains the new Field APIs, accessibility behavior, state propagation, and error presentation.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (1)
packages/ui/src/mosaic/components/field/index.ts (1)

1-2: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the new nested barrel file.

The new packages/ui/src/mosaic/components/field/index.ts re-export file conflicts with the repository rule that prohibits barrel files because they can create circular dependencies.

  • packages/ui/src/mosaic/components/field/index.ts#L1-L2: remove this barrel file.
  • packages/ui/src/mosaic/styles/index.ts#L17-L18: re-export Field and its prop types directly from ../components/field/field.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/mosaic/components/field/index.ts` around lines 1 - 2, Remove
the nested barrel file packages/ui/src/mosaic/components/field/index.ts (lines
1-2). Update the exports at packages/ui/src/mosaic/styles/index.ts (lines 17-18)
to re-export Field and its prop types directly from ../components/field/field.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/quiet-fields-compose.md:
- Around line 1-2: Replace the empty changeset frontmatter in
quiet-fields-compose.md with an `@clerk/ui` minor release entry, and add a concise
description of the new public Field compound component API.

In `@packages/swingset/src/stories/field.component.mdx`:
- Line 36: Update the Field description near the Field.Root usage note to remove
the claim that it does not propagate semantic state, while preserving the
statements that it does not validate controls or render errors automatically and
that its parts can be used independently.

In `@packages/swingset/src/stories/field.component.stories.tsx`:
- Line 1: Add the Emotion JSX import-source pragma at the beginning of the field
component story, before the existing Field import, so the styled Mosaic story
uses Emotion's JSX transform.

In `@packages/ui/src/mosaic/components/field/field.context.tsx`:
- Around line 4-10: Propagate disabled, required, and invalid state from
Field.Root to composed controls: in
packages/ui/src/mosaic/components/field/field.context.tsx lines 4-10, add typed
state fields to FieldContextValue; in
packages/ui/src/mosaic/components/field/field.tsx lines 20-37, add the states to
FieldRootProps and pass them through FieldProvider; in
packages/ui/src/mosaic/components/input/input.tsx lines 15-39, resolve explicit
control props before context values and apply the resulting disabled, required,
and aria-invalid attributes.
- Around line 67-74: Update the field context around the useSafeLayoutEffect
registration and the input relationship handling in
packages/ui/src/mosaic/components/field/field.context.tsx:67-74 and
packages/ui/src/mosaic/components/input/input.tsx:37-39 so generated Description
and Error IDs are derived during render rather than only populated by the
effect, while preserving client-side registration and cleanup. Add an SSR
assertion covering the generated aria-describedby relationships.

In `@packages/ui/src/mosaic/components/field/field.ssr.test.tsx`:
- Around line 48-62: Update Field.Root and its associated label/control ID
handling so an explicit Input id such as custom-control is preserved in SSR
markup and used for the label for attribute. Update
packages/ui/src/mosaic/components/field/field.ssr.test.tsx lines 48-62 to expect
custom-control in both locations, and update
packages/ui/src/mosaic/components/field/field.test.tsx lines 147-176 to verify
hydration preserves the server-rendered ID without adding it afterward.

---

Nitpick comments:
In `@packages/ui/src/mosaic/components/field/index.ts`:
- Around line 1-2: Remove the nested barrel file
packages/ui/src/mosaic/components/field/index.ts (lines 1-2). Update the exports
at packages/ui/src/mosaic/styles/index.ts (lines 17-18) to re-export Field and
its prop types directly from ../components/field/field.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: beecab09-0ad7-4c52-8e49-9ae6062c9e24

📥 Commits

Reviewing files that changed from the base of the PR and between 1799158 and e014d4e.

📒 Files selected for processing (14)
  • .changeset/quiet-fields-compose.md
  • packages/swingset/src/components/DocsViewer.tsx
  • packages/swingset/src/lib/registry.ts
  • packages/swingset/src/stories/field.component.mdx
  • packages/swingset/src/stories/field.component.stories.tsx
  • packages/ui/src/mosaic/components/field/field.context.tsx
  • packages/ui/src/mosaic/components/field/field.ssr.test.tsx
  • packages/ui/src/mosaic/components/field/field.styles.ts
  • packages/ui/src/mosaic/components/field/field.test.tsx
  • packages/ui/src/mosaic/components/field/field.tsx
  • packages/ui/src/mosaic/components/field/index.ts
  • packages/ui/src/mosaic/components/input/input.tsx
  • packages/ui/src/mosaic/icons/registry.tsx
  • packages/ui/src/mosaic/styles/index.ts
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • clerk/clerk_go (manual)
  • clerk/dashboard (manual)
  • clerk/accounts (manual)
  • clerk/backoffice (manual)
  • clerk/clerk (manual)
  • clerk/clerk-docs (manual)
  • clerk/cloudflare-workers (manual)
  • clerk/clerk-ios (auto-detected)
  • clerk/clerk-android (auto-detected)
  • clerk/cli (auto-detected)

Comment thread .changeset/quiet-fields-compose.md
Comment thread packages/swingset/src/stories/field.component.mdx Outdated
Comment thread packages/swingset/src/stories/field.component.stories.tsx
Comment thread packages/ui/src/mosaic/components/field/field.context.tsx
Comment thread packages/ui/src/mosaic/components/field/field.context.tsx
Comment thread packages/ui/src/mosaic/components/field/field.ssr.test.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/ui/src/mosaic/components/field/field.context.tsx (1)

117-136: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Preserve caller-provided control IDs during SSR.

Line 122 registers the supplied id only after commit. During SSR, context.controlId remains defaultControlId. Input then uses that value before its own id, so <Input id="email" /> renders with a generated ID and changes after hydration.

Derive the initial control ID during render, or provide it to FieldProvider before descendant rendering. Add an SSR test that verifies the input id and generated label htmlFor both use a caller-provided ID.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/mosaic/components/field/field.context.tsx` around lines 117 -
136, Update the control-ID derivation in the field context render path so a
caller-provided id is available during SSR, instead of relying only on the
post-commit registerControlId effect. Ensure descendants such as Input and
generated labels use that initial ID consistently, while preserving generated
IDs when no id is supplied. Add an SSR test covering both the rendered input id
and label htmlFor for a caller-provided ID.
🧹 Nitpick comments (1)
packages/ui/src/mosaic/components/field/field.tsx (1)

21-25: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the exported props interface.

Add concise JSDoc for FieldRootProps. Document that its state props apply to composed controls through field context.

As per coding guidelines, “All public APIs must be documented with JSDoc.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/mosaic/components/field/field.tsx` around lines 21 - 25, Add
concise JSDoc immediately above the exported FieldRootProps interface,
documenting the interface and clarifying that its disabled, required, and
invalid state props apply to composed controls through field context.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/ui/src/mosaic/components/field/field.context.tsx`:
- Around line 117-136: Update the control-ID derivation in the field context
render path so a caller-provided id is available during SSR, instead of relying
only on the post-commit registerControlId effect. Ensure descendants such as
Input and generated labels use that initial ID consistently, while preserving
generated IDs when no id is supplied. Add an SSR test covering both the rendered
input id and label htmlFor for a caller-provided ID.

---

Nitpick comments:
In `@packages/ui/src/mosaic/components/field/field.tsx`:
- Around line 21-25: Add concise JSDoc immediately above the exported
FieldRootProps interface, documenting the interface and clarifying that its
disabled, required, and invalid state props apply to composed controls through
field context.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: f801a372-56ed-4ed9-9d67-a21a6ba88cac

📥 Commits

Reviewing files that changed from the base of the PR and between 1ef2b96 and f592827.

📒 Files selected for processing (5)
  • packages/swingset/src/stories/field.component.mdx
  • packages/ui/src/mosaic/components/field/field.context.tsx
  • packages/ui/src/mosaic/components/field/field.test.tsx
  • packages/ui/src/mosaic/components/field/field.tsx
  • packages/ui/src/mosaic/components/input/input.tsx
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • clerk/clerk_go (manual)
  • clerk/dashboard (manual)
  • clerk/accounts (manual)
  • clerk/backoffice (manual)
  • clerk/clerk (manual)
  • clerk/clerk-docs (manual)
  • clerk/cloudflare-workers (manual)
  • clerk/cli (auto-detected)
  • clerk/clerk-ios (auto-detected)
  • clerk/clerk-android (auto-detected)
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/swingset/src/stories/field.component.mdx
  • packages/ui/src/mosaic/components/field/field.test.tsx
  • packages/ui/src/mosaic/components/input/input.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants